
/**
 * Copyright 2007 Jason Horman, Pete Aykroyd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.util.reflection;


import org.functor.UnaryFunction;

import java.lang.reflect.Array;

public class ClassUtils extends org.apache.commons.lang.ClassUtils {
	private ClassUtils() {
	}

	/**
	 * Returns the classes whose names are specified by the <code>names</code>
	 * argument, loaded with the specified classloader.
	 */
	public static Class[] loadClasses(ClassLoader loader, String[] names) throws ClassNotFoundException {
		int n = names.length;
		Class[] cls = new Class[n];
		for (int i = 0; i < n; ++i) {
			String name = names[i];
			cls[i] = loadClass(loader, name);
		}
		return cls;
	}

	/**
	 * This methods load a class given the classloader and the name of the class,
	 * and work for extended names of primitive types. <p> If you try to do
	 * ClassLoader.loadClass("boolean") it barfs it cannot find the class, so
	 * this method cope with this problem.
	 */
	public static Class loadClass(ClassLoader loader, String name) throws ClassNotFoundException {
		if (name == null) throw new ClassNotFoundException("null");

		name = name.trim();
		if (name.equals("boolean"))
			return boolean.class;
		else if (name.equals("byte"))
			return byte.class;
		else if (name.equals("char"))
			return char.class;
		else if (name.equals("short"))
			return short.class;
		else if (name.equals("int"))
			return int.class;
		else if (name.equals("long"))
			return long.class;
		else if (name.equals("float"))
			return float.class;
		else if (name.equals("double"))
			return double.class;
		else if (name.equals("java.lang.String"))
			return String.class;
		else if (name.equals("java.lang.Object"))
			return Object.class;
		else if (name.startsWith("[")) {
			// It's an array, figure out how many dimensions
			int dimension = 0;
			while (name.charAt(dimension) == '[') {
				++dimension;
			}
			char type = name.charAt(dimension);
			Class cls = null;
			switch (type) {
				case 'Z':
					cls = boolean.class;
					break;
				case 'B':
					cls = byte.class;
					break;
				case 'C':
					cls = char.class;
					break;
				case 'S':
					cls = short.class;
					break;
				case 'I':
					cls = int.class;
					break;
				case 'J':
					cls = long.class;
					break;
				case 'F':
					cls = float.class;
					break;
				case 'D':
					cls = double.class;
					break;
				case 'L':
					// Strip the semicolon at the end
					String n = name.substring(dimension + 1, name.length() - 1);
					cls = loadClass(loader, n);
					break;
			}

			if (cls == null) {
				throw new ClassNotFoundException(name);
			} else {
				int[] dim = new int[dimension];
				return Array.newInstance(cls, dim).getClass();
			}
		} else {
			if (loader != null)
				return loader.loadClass(name);
			else
				return Class.forName(name, false, null);
		}
	}

	public static java.lang.String getShortClassName(Object object) {
		return getShortClassName(object.getClass());
	}

	public static UnaryFunction<Object,Class> getClass = new UnaryFunction<Object, Class>() {
		public Class evaluate(Object object) {
			return object.getClass();
		}
	};
}
